package com.xp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xp.dto.NodeDefinitionDTO;
import com.xp.dto.NodeDefinitionRequest;
import com.xp.dto.NodeQueryRequest;
import com.xp.entity.NodeDefinition;
import com.xp.mapper.NodeDefinitionMapper;
import com.xp.service.NodeDefinitionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 节点定义服务实现类
 * 实现节点定义的业务逻辑处理
 *
 * @author xp
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class NodeDefinitionServiceImpl extends ServiceImpl<NodeDefinitionMapper, NodeDefinition> implements NodeDefinitionService {

    private final NodeDefinitionMapper nodeDefinitionMapper;
    private final ObjectMapper objectMapper;

    /**
     * 节点类型映射
     */
    private static final Map<String, String> NODE_TYPE_MAP = new HashMap<String, String>() {{
        put("START", "开始节点");
        put("END", "结束节点");
        put("COMMON", "普通节点");
        put("CONDITION", "条件节点");
        put("SWITCH", "分支节点");
        put("FOR", "循环节点");
        put("WHILE", "循环节点");
        put("BREAK", "中断节点");
        put("SUB_FLOW", "子流程节点");
    }};

    /**
     * 节点分类映射
     */
    private static final Map<String, String> CATEGORY_MAP = new HashMap<String, String>() {{
        put("BASIC", "基础节点");
        put("HTTP", "HTTP请求");
        put("DATABASE", "数据库操作");
        put("FILE", "文件操作");
        put("EMAIL", "邮件发送");
        put("SCRIPT", "脚本执行");
        put("TRANSFORM", "数据转换");
        put("TIMER", "定时器");
        put("PARALLEL", "并行处理");
        put("LOOP", "循环处理");
        put("CONDITION", "条件判断");
    }};

    /**
     * 状态映射
     */
    private static final Map<Integer, String> STATUS_MAP = new HashMap<Integer, String>() {{
        put(0, "禁用");
        put(1, "启用");
        put(2, "废弃");
    }};

    @Override
    public IPage<NodeDefinitionDTO> getNodeDefinitionPage(NodeQueryRequest request) {
        Page<NodeDefinition> page = new Page<>(request.getPageNum(), request.getPageSize());
        IPage<NodeDefinition> result = nodeDefinitionMapper.selectNodeDefinitionPage(
                page,
                request.getNodeName(),
                request.getNodeType(),
                request.getCategory(),
                request.getStatus()
        );
        
        return result.convert(this::convertToDTO);
    }

    @Override
    public NodeDefinitionDTO getNodeDefinitionById(Long id) {
        NodeDefinition nodeDefinition = nodeDefinitionMapper.selectById(id);
        return nodeDefinition != null ? convertToDTO(nodeDefinition) : null;
    }

    @Override
    public NodeDefinitionDTO getNodeDefinitionByCode(String nodeCode) {
        NodeDefinition nodeDefinition = nodeDefinitionMapper.selectByNodeCode(nodeCode);
        return nodeDefinition != null ? convertToDTO(nodeDefinition) : null;
    }

    @Override
    public NodeDefinitionDTO getNodeDefinitionByCodeAndVersion(String nodeCode, String version) {
        NodeDefinition nodeDefinition = nodeDefinitionMapper.selectByNodeCodeAndVersion(nodeCode, version);
        return nodeDefinition != null ? convertToDTO(nodeDefinition) : null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public NodeDefinitionDTO createNodeDefinition(NodeDefinitionRequest request) {
        // 验证节点编码是否已存在
        if (!validateNodeCode(request.getNodeCode(), null)) {
            throw new RuntimeException("节点编码已存在");
        }

        // 验证Schema格式
        if (StringUtils.hasText(request.getInputSchema()) && !validateSchema(request.getInputSchema())) {
            throw new RuntimeException("输入参数Schema格式不正确");
        }
        if (StringUtils.hasText(request.getOutputSchema()) && !validateSchema(request.getOutputSchema())) {
            throw new RuntimeException("输出参数Schema格式不正确");
        }
        if (StringUtils.hasText(request.getConfigSchema()) && !validateSchema(request.getConfigSchema())) {
            throw new RuntimeException("配置参数Schema格式不正确");
        }

        NodeDefinition nodeDefinition = new NodeDefinition();
        BeanUtils.copyProperties(request, nodeDefinition);
        
        // 设置默认值
        if (!StringUtils.hasText(nodeDefinition.getVersion())) {
            nodeDefinition.setVersion("1.0.0");
        }
        if (nodeDefinition.getSortOrder() == null) {
            nodeDefinition.setSortOrder(0);
        }
        nodeDefinition.setIsSystem(0); // 用户创建的节点都是非系统节点
        nodeDefinition.setCreateTime(LocalDateTime.now());
        nodeDefinition.setUpdateTime(LocalDateTime.now());
        nodeDefinition.setDeleted(0);

        nodeDefinitionMapper.insert(nodeDefinition);
        return convertToDTO(nodeDefinition);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public NodeDefinitionDTO updateNodeDefinition(Long id, NodeDefinitionRequest request) {
        NodeDefinition existingNode = nodeDefinitionMapper.selectById(id);
        if (existingNode == null) {
            throw new RuntimeException("节点定义不存在");
        }

        // 系统内置节点不允许修改核心属性
        if (existingNode.getIsSystem() == 1) {
            throw new RuntimeException("系统内置节点不允许修改");
        }

        // 验证节点编码是否已存在（排除当前节点）
        if (!validateNodeCode(request.getNodeCode(), id)) {
            throw new RuntimeException("节点编码已存在");
        }

        // 验证Schema格式
        if (StringUtils.hasText(request.getInputSchema()) && !validateSchema(request.getInputSchema())) {
            throw new RuntimeException("输入参数Schema格式不正确");
        }
        if (StringUtils.hasText(request.getOutputSchema()) && !validateSchema(request.getOutputSchema())) {
            throw new RuntimeException("输出参数Schema格式不正确");
        }
        if (StringUtils.hasText(request.getConfigSchema()) && !validateSchema(request.getConfigSchema())) {
            throw new RuntimeException("配置参数Schema格式不正确");
        }

        BeanUtils.copyProperties(request, existingNode);
        existingNode.setUpdateTime(LocalDateTime.now());

        nodeDefinitionMapper.updateById(existingNode);
        return convertToDTO(existingNode);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteNodeDefinition(Long id) {
        NodeDefinition nodeDefinition = nodeDefinitionMapper.selectById(id);
        if (nodeDefinition == null) {
            throw new RuntimeException("节点定义不存在");
        }

        // 系统内置节点不允许删除
        if (nodeDefinition.getIsSystem() == 1) {
            throw new RuntimeException("系统内置节点不允许删除");
        }

        return nodeDefinitionMapper.deleteById(id) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchDeleteNodeDefinitions(List<Long> ids) {
        // 检查是否包含系统内置节点
        List<NodeDefinition> nodes = nodeDefinitionMapper.selectBatchIds(ids);
        boolean hasSystemNode = nodes.stream().anyMatch(node -> node.getIsSystem() == 1);
        if (hasSystemNode) {
            throw new RuntimeException("不能删除系统内置节点");
        }

        return nodeDefinitionMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean enableNodeDefinition(Long id) {
        return nodeDefinitionMapper.updateStatus(id, 1) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean disableNodeDefinition(Long id) {
        return nodeDefinitionMapper.updateStatus(id, 0) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchUpdateStatus(List<Long> ids, Integer status) {
        for (Long id : ids) {
            nodeDefinitionMapper.updateStatus(id, status);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public NodeDefinitionDTO copyNodeDefinition(Long sourceId, String newNodeCode, String newNodeName, String newVersion) {
        NodeDefinition sourceNode = nodeDefinitionMapper.selectById(sourceId);
        if (sourceNode == null) {
            throw new RuntimeException("源节点定义不存在");
        }

        // 验证新节点编码是否已存在
        if (!validateNodeCode(newNodeCode, null)) {
            throw new RuntimeException("节点编码已存在");
        }

        NodeDefinition newNode = new NodeDefinition();
        BeanUtils.copyProperties(sourceNode, newNode);
        newNode.setId(null);
        newNode.setNodeCode(newNodeCode);
        newNode.setNodeName(newNodeName);
        newNode.setVersion(newVersion);
        newNode.setIsSystem(0); // 复制的节点都是非系统节点
        newNode.setCreateTime(LocalDateTime.now());
        newNode.setUpdateTime(LocalDateTime.now());

        nodeDefinitionMapper.insert(newNode);
        return convertToDTO(newNode);
    }

    @Override
    public List<NodeDefinitionDTO> getNodeDefinitionsByType(String nodeType) {
        List<NodeDefinition> nodes = nodeDefinitionMapper.selectByNodeType(nodeType);
        return nodes.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    public List<NodeDefinitionDTO> getNodeDefinitionsByCategory(String category) {
        List<NodeDefinition> nodes = nodeDefinitionMapper.selectByCategory(category);
        return nodes.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    public List<NodeDefinitionDTO> getEnabledNodeDefinitions() {
        List<NodeDefinition> nodes = nodeDefinitionMapper.selectEnabledNodes();
        return nodes.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    public List<NodeDefinitionDTO> getSystemNodeDefinitions() {
        List<NodeDefinition> nodes = nodeDefinitionMapper.selectSystemNodes();
        return nodes.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    public List<NodeDefinitionDTO> getCustomNodeDefinitions() {
        List<NodeDefinition> nodes = nodeDefinitionMapper.selectCustomNodes();
        return nodes.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    public List<String> getNodeCategories() {
        return nodeDefinitionMapper.selectCategories();
    }

    @Override
    public List<String> getNodeTypes() {
        return nodeDefinitionMapper.selectNodeTypes();
    }

    @Override
    public Map<String, Object> getNodeDefinitionStatistics() {
        // 这里需要在Mapper中实现selectStatistics方法
        Map<String, Object> statistics = new HashMap<>();
        
        LambdaQueryWrapper<NodeDefinition> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(NodeDefinition::getDeleted, 0);
        
        long totalCount = nodeDefinitionMapper.selectCount(wrapper);
        
        wrapper.eq(NodeDefinition::getStatus, 1);
        long enabledCount = nodeDefinitionMapper.selectCount(wrapper);
        
        wrapper.clear();
        wrapper.eq(NodeDefinition::getDeleted, 0).eq(NodeDefinition::getIsSystem, 1);
        long systemCount = nodeDefinitionMapper.selectCount(wrapper);
        
        statistics.put("totalCount", totalCount);
        statistics.put("enabledCount", enabledCount);
        statistics.put("disabledCount", totalCount - enabledCount);
        statistics.put("systemCount", systemCount);
        statistics.put("customCount", totalCount - systemCount);
        
        return statistics;
    }

    @Override
    public List<Map<String, Object>> getCategoryStatistics() {
        // 这里需要在Mapper中实现selectCategoryStatistics方法
        List<Map<String, Object>> result = new ArrayList<>();
        
        List<String> categories = getNodeCategories();
        for (String category : categories) {
            LambdaQueryWrapper<NodeDefinition> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(NodeDefinition::getCategory, category)
                   .eq(NodeDefinition::getDeleted, 0);
            
            long count = nodeDefinitionMapper.selectCount(wrapper);
            
            wrapper.eq(NodeDefinition::getStatus, 1);
            long enabledCount = nodeDefinitionMapper.selectCount(wrapper);
            
            Map<String, Object> stat = new HashMap<>();
            stat.put("category", category);
            stat.put("count", count);
            stat.put("enabledCount", enabledCount);
            
            result.add(stat);
        }
        
        return result;
    }

    @Override
    public Boolean validateNodeCode(String nodeCode, Long excludeId) {
        if (excludeId == null) {
            excludeId = -1L;
        }
        return nodeDefinitionMapper.checkNodeCodeExists(nodeCode, excludeId) == 0;
    }

    @Override
    public Boolean validateSchema(String schema) {
        if (!StringUtils.hasText(schema)) {
            return true;
        }
        
        try {
            JsonNode jsonNode = objectMapper.readTree(schema);
            // 简单验证是否为有效的JSON
            return jsonNode != null;
        } catch (JsonProcessingException e) {
            log.error("Schema格式验证失败: {}", e.getMessage());
            return false;
        }
    }

    @Override
    public Map<String, Object> testNodeDefinition(Long id, Map<String, Object> testData) {
        NodeDefinition nodeDefinition = nodeDefinitionMapper.selectById(id);
        if (nodeDefinition == null) {
            throw new RuntimeException("节点定义不存在");
        }

        Map<String, Object> result = new HashMap<>();
        result.put("nodeCode", nodeDefinition.getNodeCode());
        result.put("nodeName", nodeDefinition.getNodeName());
        result.put("testData", testData);
        result.put("testTime", LocalDateTime.now());
        result.put("success", true);
        result.put("message", "测试成功");
        
        // 这里可以根据实际需要实现节点测试逻辑
        
        return result;
    }

    @Override
    public String exportNodeDefinitions(List<Long> ids) {
        List<NodeDefinition> nodes;
        if (ids == null || ids.isEmpty()) {
            LambdaQueryWrapper<NodeDefinition> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(NodeDefinition::getDeleted, 0);
            nodes = nodeDefinitionMapper.selectList(wrapper);
        } else {
            nodes = nodeDefinitionMapper.selectBatchIds(ids);
        }
        
        try {
            return objectMapper.writeValueAsString(nodes);
        } catch (JsonProcessingException e) {
            log.error("导出节点定义失败: {}", e.getMessage());
            throw new RuntimeException("导出失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> importNodeDefinitions(String data) {
        try {
            List<NodeDefinition> nodes = objectMapper.readValue(data, 
                objectMapper.getTypeFactory().constructCollectionType(List.class, NodeDefinition.class));
            
            int successCount = 0;
            int failCount = 0;
            List<String> errors = new ArrayList<>();
            
            for (NodeDefinition node : nodes) {
                try {
                    // 重置ID和时间
                    node.setId(null);
                    node.setCreateTime(LocalDateTime.now());
                    node.setUpdateTime(LocalDateTime.now());
                    node.setDeleted(0);
                    
                    // 检查节点编码是否已存在
                    if (!validateNodeCode(node.getNodeCode(), null)) {
                        // 如果存在，生成新的编码
                        String originalCode = node.getNodeCode();
                        int suffix = 1;
                        while (!validateNodeCode(originalCode + "_" + suffix, null)) {
                            suffix++;
                        }
                        node.setNodeCode(originalCode + "_" + suffix);
                    }
                    
                    nodeDefinitionMapper.insert(node);
                    successCount++;
                } catch (Exception e) {
                    failCount++;
                    errors.add("节点 " + node.getNodeName() + " 导入失败: " + e.getMessage());
                }
            }
            
            Map<String, Object> result = new HashMap<>();
            result.put("successCount", successCount);
            result.put("failCount", failCount);
            result.put("errors", errors);
            
            return result;
        } catch (JsonProcessingException e) {
            log.error("导入节点定义失败: {}", e.getMessage());
            throw new RuntimeException("导入数据格式不正确");
        }
    }

    /**
     * 将实体转换为DTO
     *
     * @param nodeDefinition 节点定义实体
     * @return 节点定义DTO
     */
    private NodeDefinitionDTO convertToDTO(NodeDefinition nodeDefinition) {
        NodeDefinitionDTO dto = new NodeDefinitionDTO();
        BeanUtils.copyProperties(nodeDefinition, dto);
        
        // 设置扩展字段
        dto.setNodeTypeName(NODE_TYPE_MAP.get(nodeDefinition.getNodeType()));
        dto.setCategoryName(CATEGORY_MAP.get(nodeDefinition.getCategory()));
        dto.setStatusName(STATUS_MAP.get(nodeDefinition.getStatus()));
        dto.setEditable(nodeDefinition.getIsSystem() == 0);
        dto.setDeletable(nodeDefinition.getIsSystem() == 0);
        
        // 解析JSON字段
        try {
            if (StringUtils.hasText(nodeDefinition.getInputSchema())) {
                dto.setInputConfig(objectMapper.readValue(nodeDefinition.getInputSchema(), Object.class));
            }
            if (StringUtils.hasText(nodeDefinition.getOutputSchema())) {
                dto.setOutputConfig(objectMapper.readValue(nodeDefinition.getOutputSchema(), Object.class));
            }
            if (StringUtils.hasText(nodeDefinition.getConfigSchema())) {
                dto.setNodeConfig(objectMapper.readValue(nodeDefinition.getConfigSchema(), Object.class));
            }
            if (StringUtils.hasText(nodeDefinition.getDefaultConfig())) {
                dto.setDefaultConfigObj(objectMapper.readValue(nodeDefinition.getDefaultConfig(), Object.class));
            }
        } catch (JsonProcessingException e) {
            log.warn("解析节点配置JSON失败: {}", e.getMessage());
        }
        
        return dto;
    }
}